package be.android.forap.javacard;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.HashMap;

import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.simalliance.openmobileapi.Channel;
import org.simalliance.openmobileapi.Reader;
import org.simalliance.openmobileapi.SEService;
import org.simalliance.openmobileapi.Session;

import be.android.forap.crypto.CryptoUtil;
import be.android.forap.gui.EncryptActivity;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.smartcard.CardException;
//import android.util.Log;
import android.widget.Toast;

public class SecureElement implements SEService.CallBack{

	private final static String TAG = "SecurityCard";

	//private static boolean connected;
	//private static int disconnects;
	private static Reader[] readers;

	public static Reader[] getAllSmartCardReaders() {
		if(seService != null)
			return seService.getReaders();
		return null;
	}

	public static Reader[] getSecureSmartCardReaders() {
		return readers;
	}

	//private static Channel channel;
	private static Activity main;
	public static SEService seService;
	//private static HashMap<String, Reader> accountToReader = new HashMap<String, Reader>();
	//private static HashMap<String, Session> sessionToReader = new HashMap<String, Session>();

	private SecureElement() {
	}

	public static final void init(Activity main ) {
		SecureElement.main = main;
		//accountToReader.clear();
		//sessionToReader.clear();

		try {
			new SEService(main.getApplicationContext(), new SecureElement() );
		} catch (SecurityException e) {
			//Log.e(TAG, "Smartcard service binding not allowed");
		} catch (Exception e) {
			//Log.e(TAG, "Exception: " + e.getMessage());
		}
	}

	@Override
	public void serviceConnected(SEService service) {
		//Log.i(TAG, "seviceConnected()");
		try {
			seService = service;
			readers = initReader(seService.getReaders());

		} catch (Exception e) {
			Toast.makeText(main,
					"Could not access the terminal: " + e,
					Toast.LENGTH_LONG).show();
			return;
		}

		//connected = true;

		//main.refresh();
	}



	private static Reader[] initReader(Reader[] availableReader){
		//Log.d(TAG, "Retrieve available readers...");	

		ArrayList<Reader> readerlist = new ArrayList<Reader>();
		//accountToReader.clear();
		for( Reader r : availableReader ){
			if( r.isSecureElementPresent() ){
				Session session = null;
				Channel channel = null;
				try {
					session = r.openSession();
					channel = session.openLogicalChannel(Commands.selectAID_APDU);
					if( channel != null ){
						readerlist.add(r);
						channel.close();
					}
					session.close();
				} catch (Exception e) {
					if( channel != null ){
						channel.close();
					}
					if( session != null ){
						session.close();
					}
				} 
			}
		}
		return readerlist.toArray(new Reader[readerlist.size()]);
	}

	private static final boolean ensureConnected() {
		if (!seService.isConnected())
			Toast.makeText(
					main,
					"Could not establish connection to the smartcard service. "
							+ "Please try again.", Toast.LENGTH_LONG).show();
		return seService.isConnected();
	}

	private static final Channel openChannelAndSelect(Reader reader) throws IOException {

		if( reader == null ){
			return null;
		}
		Channel cardChannel;
		try {
			Session session = reader.openSession();
			cardChannel = session.openLogicalChannel( Commands.selectAID_APDU );

		} catch (IOException e) {
			throw new IOException("Could not open session/channel on terminal " + reader.getName() );
		}

		return cardChannel;
	}

	public static final void shutdown() {
		//readers.closeSessions();
		if (seService != null) {
			seService.shutdown();
			seService = null;
		}
	}



	public static boolean isSecureElementPresent(){
		if(readers == null)
			return false;
		if(readers.length == 0)
			return false;
		return readers[0].isSecureElementPresent();
	}

	public static byte[] getPTBuffer() throws IOException{

		Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Initialize encryption
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send init aes APDU command");
		byte[] respApdu = channel.transmit(Commands.ptBuffer);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));
		//outputStream.write(resp);

		channel.close();

		return resp;
	}
	
	public static byte[] initDataEncryption() throws IOException{

		Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Initialize encryption
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send init aes APDU command");
		byte[] respApdu = channel.transmit(Commands.initDataEncryption);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));
		//outputStream.write(resp);

		channel.close();

		return resp;
	}
	
	public static byte[] updateDataEncryption(byte[] data) throws IOException{
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Initialize encryption
		 */
		byte[] sw = new byte[2];

		//Log.d(TAG, "Send update APDU commands");
		int remaining = data.length;
		//Log.d(TAG, "Remaining length "+remaining);
		int i = 0;
		int blockLength = 255;
		while(remaining>blockLength){
			byte[] textToSend = new byte[blockLength];
			System.arraycopy(data,i*blockLength, textToSend, 0, blockLength);
			byte[] putDataApdu = Commands.getUpdateEncryptDataApdu(textToSend);
			byte[] respApdu = channel.transmit(putDataApdu);

			byte[] resp = new byte[respApdu.length - 2];
			System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
			out.write(resp);
			
			remaining -= blockLength;
			//Log.d(TAG, "Remaining length "+remaining);
			i++;
		}
		
		byte[] lastText = new byte[remaining];
		System.arraycopy(data,i*blockLength, lastText, 0, remaining);

		byte[] lastPutDataApdu = Commands.getUpdateEncryptDataApdu(lastText);
		byte[] lastRespApdu = channel.transmit(lastPutDataApdu);


		remaining -= remaining;
		//Log.d(TAG, "Remaining length "+remaining);

		sw  = new byte[]{lastRespApdu[lastRespApdu.length - 2],lastRespApdu[lastRespApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +lastRespApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[lastRespApdu.length - 2];
		System.arraycopy(lastRespApdu, 0, resp, 0, lastRespApdu.length - 2);
		out.write(resp);

		channel.close();
		
		return out.toByteArray();
	}
	
	public static byte[] doFinalDataEncryption() throws IOException{
		Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Initialize encryption
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send do final APDU command");
		byte[] respApdu = channel.transmit(Commands.finalizeDataEncryption);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));
		//outputStream.write(resp);

		channel.close();

		byte out[] = resp;//outputStream.toByteArray();
		//Log.e(TAG, "lenght out "+out.length);		
		
		return resp;
	}
	
	public static void putPublicKey(Key key) throws IOException {
		//Log.d(TAG, CryptoUtil.toHex(key.getEncoded()));
		RSAPublicKey rsaK  = (RSAPublicKey)key;
		//Log.d(TAG,CryptoUtil.toHex(rsaK.getEncoded()));
		BigInteger exp = rsaK.getPublicExponent();
		BigInteger mod = rsaK.getModulus();
		//Log.d(TAG, "exp " + exp);
		//Log.d(TAG,"mod "+ mod);
		byte[] e = exp.toByteArray();
		byte[] m = mod.toByteArray();
		test = mod;
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		outputStream.write(e);
		outputStream.write(m);

		byte[] pk = outputStream.toByteArray();


		Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Import public key
		 */

		putData(channel, pk);

		/**
		 * Set the publickey
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send get secret APDU command");
		byte[] respApdu = channel.transmit(Commands.setPublicKey);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));
		//outputStream.write(resp);

		channel.close();

		byte out[] = resp;//outputStream.toByteArray();
		//Log.e(TAG, "lenght out "+out.length);
	}

	static BigInteger test;

	public static void putPrivateKey(PrivateKey key) throws IOException {
		//Log.d(TAG, CryptoUtil.toHex(key.getEncoded()));
		RSAPrivateKey rsaK  = (RSAPrivateKey)key;
		//Log.d(TAG,CryptoUtil.toHex(rsaK.getEncoded()));
		BigInteger exp = rsaK.getPrivateExponent();
		BigInteger mod = rsaK.getModulus();
		//Log.d(TAG, "exp " + exp);
		//Log.d(TAG,"mod "+ mod);
		/*Log.d(TAG,"mod1 "+ test);
		Log.d(TAG,"mod "+ mod.equals(test));*/
		byte[] ske = exp.toByteArray();
		byte[] skm = mod.toByteArray();

		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		//outputStream.write(e);
		//outputStream.write(m);

		//byte[] sk = e;// outputStream.toByteArray();

		Channel channel;
		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Import private key exp
		 */

		putData(channel, ske);

		/**
		 * Set the pirvate key exp
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send put secret mod APDU command");
		byte[] respApdu = channel.transmit(Commands.setPrivateKeyExp);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));		
		
		/**
		 * Import private key mod
		 */

		putData(channel, skm);

		/**
		 * Set the pirvate key mod
		 */
		byte[] sw2 = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send put secret exp APDU command");
		byte[] respApdu2 = channel.transmit(Commands.setPrivateKeyMod);

		sw  = new byte[]{respApdu2[respApdu2.length - 2],respApdu2[respApdu2.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu2.length);
		//Log.e(TAG, "sw : " +bin2hex(sw2));

		// Parse response APDU and show text but remove SW1 SW2 first 
		
		channel.close();

	}
	
	public static void encryptRSA() throws IOException {
		Channel channel;	

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Import public key
		 */

		generateSessionKey(channel);

		/**
		 * Encrpyt data
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send get secret APDU command");
		byte[] respApdu = channel.transmit(Commands.encryptSessionData);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));
		//outputStream.write(resp);

		channel.close();

		byte out[] = resp;//outputStream.toByteArray();
		//Log.e(TAG, "lenght out "+out.length);

	}
	
	public static void encryptRSA(byte[] sessionInfo) throws IOException {
		Channel channel;	

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Import session info
		 */

		putData(channel, sessionInfo);

		/**
		 * Encrpyt data
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send get secret APDU command");
		byte[] respApdu = channel.transmit(Commands.encryptSessionData);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));
		//outputStream.write(resp);

		channel.close();

		byte out[] = resp;//outputStream.toByteArray();
		//Log.e(TAG, "lenght out "+out.length);

	}

	public static byte[] decryptRSA(byte[] ciphertext) throws IOException {
		Channel channel;	

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");
		/**
		 * Import public key
		 */

		putData(channel, ciphertext);

		/**
		 * Encrpyt data
		 */
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send get decrypt APDU command");
		byte[] respApdu = channel.transmit(Commands.decryptSessionData);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		channel.close();		
		/**
		 * get data
		 */
		return getData();
	}
	
	private static void generateSessionKey(Channel channel) throws IOException{
		/*Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");*/

	
		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send generate secret APDU command");
		byte[] respApdu = channel.transmit(Commands.generateSessionKey);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));


	}

	private static void putData(Channel channel, byte [] data) throws IOException{
		/*Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");*/

		//Log.d(TAG, "Send put APDU commands");
		int remaining = data.length;
		//Log.d(TAG, "Total length "+remaining);
		int i = 0;
		boolean success = true;
		int blockLength = 255;
		while(remaining>blockLength){
			byte[] textToSend = new byte[blockLength];
			System.arraycopy(data,i*blockLength, textToSend, 0, blockLength);
			byte[] putDataApdu = Commands.getImportDataApdu(textToSend, true);
			byte[] respApdu = channel.transmit(putDataApdu);

			//Log.d(TAG, "Response apdu "+bin2hex(respApdu));
			if(!(respApdu.length == 2 && respApdu[0] == (byte)0x90 && respApdu[1] == (byte)0x00)){
				//Log.d(TAG, "SW Response apdu "+bin2hex(respApdu));
				success = false;
			}
			remaining -= blockLength;
			//Log.d(TAG, "Remaining length "+remaining);
			i++;
		}

		byte[] textToSend = new byte[remaining];
		System.arraycopy(data,i*blockLength, textToSend, 0, remaining);

		byte[] lastPutDataApdu = Commands.getImportDataApdu(textToSend, false);
		byte[] lastRespApdu = channel.transmit(lastPutDataApdu);


		remaining -= remaining;
		//Log.d(TAG, "Remaining length "+remaining);

		//channel.close();

		// Parse response APDU and show text but remove SW1 SW2 first 
		/*Log.d(TAG, "Response apdu "+bin2hex(lastRespApdu));
		Log.d(TAG, "Response apdu "+success);
		Log.d(TAG, "Response apdu "+String.valueOf(lastRespApdu.length == 2));
		Log.d(TAG, "Response apdu "+String.valueOf(lastRespApdu[0] == (byte)0x90));
		Log.d(TAG, "Response apdu "+String.valueOf(lastRespApdu[1] == (byte)0x00));
		if(success && lastRespApdu.length == 2 && lastRespApdu[0] == (byte)0x90 && lastRespApdu[1] == (byte)0x00){
			Log.d(TAG,"Succesfull processing. response: "+bin2hex(lastRespApdu));
		}else{
			Log.d(TAG,"ERROR unsuccesfull processing. response: "+bin2hex(lastRespApdu));
		}*/
	}

	public static byte [] getData() throws IOException{
		Channel channel;

		channel = initChannel();
		if(channel == null)
			throw new IOException("Secure Element not present");

		byte[] sw = new byte[2];
		//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		//Log.d(TAG, "Send get data APDU command");
		byte[] respApdu = channel.transmit(Commands.exportData);

		sw  = new byte[]{respApdu[respApdu.length - 2],respApdu[respApdu.length - 1]};
		//Log.e(TAG, "recieved length : " +respApdu.length);
		//Log.e(TAG, "sw : " +bin2hex(sw));

		// Parse response APDU and show text but remove SW1 SW2 first 
		byte[] resp = new byte[respApdu.length - 2];
		System.arraycopy(respApdu, 0, resp, 0, respApdu.length - 2);
		//Log.e(TAG, resp.length + new String(resp));
		//outputStream.write(resp);

		channel.close();

		byte out[] = resp;//outputStream.toByteArray();
		//Log.e(TAG, "lenght out "+out.length);
		return out;
	}

	private static Channel initChannel() throws IOException {
		if (!ensureConnected())
			return null;

		Channel cardChannel = null;
		if( readers == null || readers.length == 0 ){
			return null;
		}

		cardChannel = openChannelAndSelect(readers[0]);
		return cardChannel;
	}



	private static String bin2hex(byte[] data) {
		return String.format("%0" + (data.length * 2) + 'x', new BigInteger(1, data));
	}
}

/*public byte[] encryptRSA_PKCS1(byte[] pt){
//		try {
//			Log.d(TAG, "Create Session from the first reader...");
//			Session session = readers[0].openSession();
//
//			Log.d(TAG, "Create logical channel within the session...");
//			Channel channel = session.openLogicalChannel(new byte[] {
//					(byte) 0xD2, 0x76, 0x00, 0x01, 0x16, 0x00, 0x04,
//					(byte) 0xFF, 0x49, 0x50, 0x25, (byte) 0x89,
//					(byte) 0xC0, 0x01, (byte) 0x9B, 0x01 });
//			/*Channel channel = session.openLogicalChannel(new byte[] {
//							(byte) 0xD2, 0x76, 0x00, 0x01, 0x18, 0x00, 0x02,
//							(byte) 0xFF, 0x49, 0x50, 0x25, (byte) 0x89,
//							(byte) 0xC0, 0x01, (byte) 0x9B, 0x01 });*/
//
//			Log.d(TAG, "Send HelloWorld APDU command");
//			byte[] respApdu = channel.transmit(new byte[] {
//					(byte) 0x90, 0x10, 0x00, 0x00, 0x00 });
//
//			channel.close();
//
//			// Parse response APDU and show text but remove SW1 SW2 first 
//			byte[] helloStr = new byte[respApdu.length - 2];
//
//			System.arraycopy(respApdu, 0, helloStr, 0, respApdu.length - 2);
//			Log.e(LOG_TAG, "LEngth : " +respApdu.length+ " -2 = "+ helloStr.length+ " : " +bin2hex(respApdu)+"->"+bin2hex(helloStr));
//			Toast.makeText(MainActivity.this, new String(helloStr),   Toast.LENGTH_LONG).show();
//		} catch (Exception e) {
//			Log.e(LOG_TAG, "Error occured:", e);
//			return;
//		} 
//	return null;
//}

//Button digest = (Button) findViewById(R.id.digest);
//digest.setOnClickListener(new OnClickListener() {
//	public void onClick(View v) {
//		try {
//			Log.d(LOG_TAG, "Retrieve available readers...");
//			Reader[] readers = seService.getReaders();
//			if (readers.length < 1)
//				return;
//			Log.d(LOG_TAG, "This app has " + readers.length + " readers...");
//
//			Log.d(LOG_TAG, "Create Session from the first reader...");
//			Session session = readers[0].openSession();
//
//			if(!readers[0].isSecureElementPresent())
//				Toast.makeText(MainActivity.this, "Secure element absent",   Toast.LENGTH_LONG).show();
//
//			Log.d(LOG_TAG, "Create logical channel within the session...");
//			Channel channel = session.openLogicalChannel(new byte[] {
//					(byte) 0xD2, 0x76, 0x00, 0x01, 0x16, 0x00, 0x04,
//					(byte) 0xFF, 0x49, 0x50, 0x25, (byte) 0x89,
//					(byte) 0xC0, 0x01, (byte) 0x9B, 0x01 });
//
//			Log.d(LOG_TAG, "Send digest APDU command");
//			//Digest
//			String clearText = ((EditText) findViewById(R.id.editText)).getText().toString();
//			byte[] tail = clearText.getBytes();
//			byte[] head = new byte[] {	(byte) 0x90, 0x60, 0x00, 0x00, (byte)tail.length };
//			// digest apdu
//			byte[] in = new byte[head.length + tail.length];
//			System.arraycopy(head, 0, in, 0, head.length);
//			System.arraycopy(tail, 0, in, head.length, tail.length);
//
//			byte[] respApdu = channel.transmit(in);
//
//			channel.close();
//
//			// Parse response APDU and show text but remove SW1 SW2 first 
//			byte[] helloStr = new byte[respApdu.length - 2];
//
//			System.arraycopy(respApdu, 0, helloStr, 0, respApdu.length - 2);
//			Log.e(LOG_TAG, "LEngth : " +respApdu.length+ " -2 = "+ helloStr.length+ " : " +bin2hex(respApdu)+"->"+bin2hex(helloStr));
//			//Toast.makeText(MainActivity.this, new String(helloStr),   Toast.LENGTH_LONG).show();
//			Toast.makeText(MainActivity.this, bin2hex(helloStr), Toast.LENGTH_LONG).show();
//			TextView output = (TextView) findViewById(R.id.digestResult);
//			byte[] bytesOfMessage = clearText.getBytes();
//			MessageDigest md = MessageDigest.getInstance("SHA-256");
//			byte[] thedigest = md.digest(bytesOfMessage);
//			//output.setText("sdcard: " + new String(helloStr) + "\n" + "java: " + bin2hex(thedigest) );
//			output.setText("sdcard: " + bin2hex(helloStr) + "\n" + "java: " + bin2hex(thedigest) );
//		} catch (Exception e) {
//			Log.e(LOG_TAG, "Error occured:", e);
//			return;
//		} 
//	}
//});